home *** CD-ROM | disk | FTP | other *** search
/ Acorn RISC PD-CD 1 / Acorn RISC PD-CD 1.iso / languages / gawk / c / io < prev    next >
Encoding:
Text File  |  1990-02-22  |  14.2 KB  |  662 lines

  1. /*
  2.  * io.c - routines for dealing with input and output and records
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27. #include <signal.h>
  28.  
  29. static void do_file();
  30. static IOBUF *nextfile();
  31. static int get_a_record();
  32. static int iop_close();
  33. static IOBUF *iop_alloc();
  34. static void close_one();
  35. static int close_redir();
  36. static IOBUF *gawk_popen();
  37. static int gawk_pclose();
  38.  
  39. static struct redirect *red_head = NULL;
  40. static int getline_redirect = 0;    /* "getline <file" being executed */
  41.  
  42. extern char *line_buf;
  43. extern NODE *ARGC_node;
  44. extern NODE *ARGV_node;
  45. extern NODE **fields_arr;
  46.  
  47. int field_num;
  48.  
  49. static IOBUF *
  50. nextfile()
  51. {
  52.     static int i = 1;
  53.     static int files = 0;
  54.     static IOBUF *curfile = NULL;
  55.     char *arg;
  56.     char *cp;
  57.     FILE *fp = NULL;
  58.  
  59.     if (curfile != NULL && curfile->cnt != EOF)
  60.         return curfile;
  61.     for (; i < (int) (ARGC_node->lnode->numbr); i++) {
  62.         arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
  63.         if (*arg == '\0')
  64.             continue;
  65.         cp = strchr(arg, '=');
  66.         if (cp != NULL) {
  67.             *cp++ = '\0';
  68.             variable(arg)->var_value = make_string(cp, strlen(cp));
  69.             *--cp = '=';    /* restore original text of ARGV */
  70.         } else {
  71.             files++;
  72.             if (STREQ(arg, "-"))
  73.                 fp = stdin;
  74.             else
  75.                 fp = devopen(arg, "r");
  76.             if (fp == NULL)
  77.                 fatal("cannot open file `%s' for reading", arg);
  78.             /* This is a kludge.  */
  79.             deref = FILENAME_node->var_value;
  80.             do_deref();
  81.             FILENAME_node->var_value =
  82.                 make_string(arg, strlen(arg));
  83.             FNR_node->var_value->numbr = 0.0;
  84.             i++;
  85.             break;
  86.         }
  87.     }
  88.     if (files == 0) {
  89.         files++;
  90.         /* no args. -- use stdin */
  91.         /* FILENAME is init'ed to "-" */
  92.         /* FNR is init'ed to 0 */
  93.         fp = stdin;
  94.     }
  95.     if (fp == NULL)
  96.         return NULL;
  97.     return curfile = iop_alloc(fp);
  98. }
  99.  
  100. static IOBUF *
  101. iop_alloc(fp)
  102. FILE *fp;
  103. {
  104.     IOBUF *iop;
  105.  
  106.     if (fp == NULL)
  107.         return NULL;
  108.     emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile");
  109.     iop->flag = 0;
  110.     iop->size = BUFSIZ;
  111.     iop->fp = fp;
  112.     emalloc(iop->buf, char *, iop->size, "nextfile");
  113.     iop->off = iop->buf;
  114.     iop->cnt = 0;
  115.     iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ;
  116.     emalloc(iop->secbuf, char *, iop->secsiz, "nextfile");
  117.     return iop;
  118. }
  119.  
  120. void
  121. do_input()
  122. {
  123.     IOBUF *iop;
  124.     extern int exiting;
  125.  
  126.     while ((iop = nextfile()) != NULL) {
  127.         do_file(iop);
  128.         if (exiting)
  129.             break;
  130.     }
  131. }
  132.  
  133. static int
  134. iop_close(iop)
  135. IOBUF *iop;
  136. {
  137.     int ret = 0;
  138.  
  139.     if (iop->fp)
  140.     {
  141.         ret = fclose(iop->fp);
  142.         if (ret == EOF)
  143.             warning("close of file failed");
  144.     }
  145.     free(iop->buf);
  146.     free(iop->secbuf);
  147.     free((char *)iop);
  148.     return ret == EOF ? 1 : 0;
  149. }
  150.  
  151. /*
  152.  * This reads in a record from the input file
  153.  */
  154. static int
  155. inrec(iop)
  156. IOBUF *iop;
  157. {
  158.     int cnt;
  159.     int retval = 0;
  160.  
  161.     cnt = get_a_record(&line_buf, iop);
  162.  
  163.     if (cnt == EOF) {
  164.         cnt = 0;
  165.         retval = 1;
  166.     } else {
  167.         if (!getline_redirect) {
  168.             assign_number(&NR_node->var_value,
  169.                 NR_node->var_value->numbr + 1.0);
  170.             assign_number(&FNR_node->var_value,
  171.                 FNR_node->var_value->numbr + 1.0);
  172.         }
  173.     }
  174.     set_record(line_buf, cnt);
  175.  
  176.     return retval;
  177. }
  178.  
  179. static void
  180. do_file(iop)
  181. IOBUF *iop;
  182. {
  183.     /* This is where it spends all its time.  The infamous MAIN LOOP */
  184.     if (inrec(iop) == 0)
  185.         while (interpret(expression_value) && inrec(iop) == 0)
  186.             ;
  187.     (void) iop_close(iop);
  188. }
  189.  
  190. int
  191. get_rs()
  192. {
  193.     register NODE *tmp;
  194.  
  195.     tmp = force_string(RS_node->var_value);
  196.     if (tmp->stlen == 0)
  197.         return 0;
  198.     return *(tmp->stptr);
  199. }
  200.  
  201. /* Redirection for printf and print commands */
  202. struct redirect *
  203. redirect(tree, errflg)
  204. NODE *tree;
  205. int *errflg;
  206. {
  207.     register NODE *tmp;
  208.     register struct redirect *rp;
  209.     register char *str;
  210.     int tflag = 0;
  211.     int outflag = 0;
  212.     char *direction = "to";
  213.     char *mode;
  214.     FILE *fp;
  215.  
  216.     switch (tree->type) {
  217.     case Node_redirect_append:
  218.         tflag = RED_APPEND;
  219.     case Node_redirect_output:
  220.         outflag = (RED_FILE|RED_WRITE);
  221.         tflag |= outflag;
  222.         break;
  223.     case Node_redirect_pipe:
  224.         tflag = (RED_PIPE|RED_WRITE);
  225.         break;
  226.     case Node_redirect_pipein:
  227.         tflag = (RED_PIPE|RED_READ);
  228.         break;
  229.     case Node_redirect_input:
  230.         tflag = (RED_FILE|RED_READ);
  231.         break;
  232.     default:
  233.         fatal ("invalid tree type %d in redirect()", tree->type);
  234.         break;
  235.     }
  236.     tmp = force_string(tree_eval(tree->subnode));
  237.     str = tmp->stptr;
  238.     for (rp = red_head; rp != NULL; rp = rp->next)
  239.         if (STREQ(rp->value, str)
  240.             && (rp->flag == tflag
  241.             || (outflag
  242.                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
  243.             break;
  244.     if (rp == NULL) {
  245.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  246.             "redirect");
  247.         emalloc(str, char *, tmp->stlen+1, "redirect");
  248.         memcpy(str, tmp->stptr, tmp->stlen+1);
  249.         rp->value = str;
  250.         rp->flag = tflag;
  251.         rp->offset = 0;
  252.         rp->fp = NULL;
  253.         rp->iop = NULL;
  254.         /* maintain list in most-recently-used first order */
  255.         if (red_head)
  256.             red_head->prev = rp;
  257.         rp->prev = NULL;
  258.         rp->next = red_head;
  259.         red_head = rp;
  260.     }
  261.     while (rp->fp == NULL && rp->iop == NULL) {
  262.         mode = NULL;
  263.         switch (tree->type) {
  264.         case Node_redirect_output:
  265.             mode = "w";
  266.             break;
  267.         case Node_redirect_append:
  268.             mode = "a";
  269.             break;
  270.         case Node_redirect_pipe:
  271.             if ((rp->fp = popen(str, "w")) == NULL)
  272.                 fatal("can't open pipe (\"%s\") for output", str);
  273.             break;
  274.         case Node_redirect_pipein:
  275.             direction = "from";
  276.             if (gawk_popen(str, rp) == NULL)
  277.                 fatal("can't open pipe (\"%s\") for input", str);
  278.             break;
  279.         case Node_redirect_input:
  280.             direction = "from";
  281.             rp->iop = iop_alloc(devopen(str, "r"));
  282.             break;
  283.         default:
  284.             cant_happen();
  285.         }
  286.         if (mode != NULL) {
  287.             fp = devopen(str, mode);
  288.             if (fp != NULL) {
  289.                 rp->fp = fp;
  290.             }
  291.         }
  292.         if (rp->fp == NULL && rp->iop == NULL) {
  293. #if 0 /* We can't tell on RISC OS! */
  294.             /* too many files open -- close one and try again */
  295.             if (errno == ENFILE || errno == EMFILE)
  296.                 close_one();
  297.             else {
  298. #endif
  299.                 /*
  300.                  * Some other reason for failure.
  301.                  *
  302.                  * On redirection of input from a file,
  303.                  * just return an error, so e.g. getline
  304.                  * can return -1.  For output to file,
  305.                  * complain. The shell will complain on
  306.                  * a bad command to a pipe.
  307.                  */
  308.                 *errflg = 1;
  309.                 if (tree->type == Node_redirect_output
  310.                     || tree->type == Node_redirect_append)
  311.                     fatal("can't redirect %s `%s' (%s)",
  312.                         direction, str, strerror(errno));
  313.                 else
  314.                     return NULL;
  315. #if 0
  316.             }
  317. #endif
  318.         }
  319.     }
  320.     if (rp->offset != 0)    /* this file was previously open */
  321.         if (fseek(rp->fp, rp->offset, 0) == -1)
  322.             fatal("can't seek to %ld on `%s'", rp->offset, str);
  323.     free_temp(tmp);
  324.     return rp;
  325. }
  326.  
  327. static void
  328. close_one()
  329. {
  330.     register struct redirect *rp;
  331.     register struct redirect *rplast = NULL;
  332.  
  333.     /* go to end of list first, to pick up least recently used entry */
  334.     for (rp = red_head; rp != NULL; rp = rp->next)
  335.         rplast = rp;
  336.     /* now work back up through the list */
  337.     for (rp = rplast; rp != NULL; rp = rp->prev)
  338.         if (rp->fp && (rp->flag & RED_FILE)) {
  339.             rp->offset = ftell(rp->fp);
  340.             if (fclose(rp->fp))
  341.                 warning("close of \"%s\" failed.", rp->value);
  342.             rp->fp = NULL;
  343.             break;
  344.         }
  345.     if (rp == NULL)
  346.         /* surely this is the only reason ??? */
  347.         fatal("too many pipes or input files open"); 
  348. }
  349.  
  350. NODE *
  351. do_close(tree)
  352. NODE *tree;
  353. {
  354.     NODE *tmp;
  355.     register struct redirect *rp;
  356.  
  357.     tmp = force_string(tree_eval(tree->subnode));
  358.     for (rp = red_head; rp != NULL; rp = rp->next) {
  359.         if (STREQ(rp->value, tmp->stptr))
  360.             break;
  361.     }
  362.     free_temp(tmp);
  363.     if (rp == NULL) /* no match */
  364.         return tmp_number((AWKNUM) 0.0);
  365.     fflush(stdout);    /* synchronize regular output */
  366.     return tmp_number((AWKNUM)close_redir(rp));
  367. }
  368.  
  369. static int
  370. close_redir(rp)
  371. register struct redirect *rp;
  372. {
  373.     int status = 0;
  374.  
  375.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  376.         status = pclose(rp->fp);
  377.     else if (rp->fp)
  378.         status = fclose(rp->fp);
  379.     else if (rp->iop) {
  380.         if (rp->flag & RED_PIPE)
  381.             status = gawk_pclose(rp);
  382.         else
  383.             status = iop_close(rp->iop);
  384.  
  385.     }
  386.     /* SVR4 awk checks and warns about status of close */
  387.     if (status)
  388.         warning("failure status (%d) on %s close of \"%s\".",
  389.             status,
  390.             (rp->flag & RED_PIPE) ? "pipe" :
  391.             "file", rp->value);
  392.     if (rp->next)
  393.         rp->next->prev = rp->prev;
  394.     if (rp->prev)
  395.         rp->prev->next = rp->next;
  396.     else
  397.         red_head = rp->next;
  398.     free(rp->value);
  399.     free((char *)rp);
  400.     return status;
  401. }
  402.  
  403. int
  404. flush_io ()
  405. {
  406.     register struct redirect *rp;
  407.     int status = 0;
  408.  
  409.     if (fflush(stdout)) {
  410.         warning("error writing standard output.");
  411.         status++;
  412.     }
  413.     if (fflush(stderr)) {
  414.         warning("error writing standard error.");
  415.         status++;
  416.     }
  417.     for (rp = red_head; rp != NULL; rp = rp->next)
  418.         /* flush both files and pipes, what the heck */
  419.         if ((rp->flag & RED_WRITE) && rp->fp != NULL)
  420.             if (fflush(rp->fp)) {
  421.                 warning("%s flush of \"%s\" failed.",
  422.                     (rp->flag  & RED_PIPE) ? "pipe" :
  423.                     "file", rp->value);
  424.                 status++;
  425.             }
  426.     return status;
  427. }
  428.  
  429. int
  430. close_io ()
  431. {
  432.     register struct redirect *rp;
  433.     int status = 0;
  434.  
  435.     for (rp = red_head; rp != NULL; rp = rp->next)
  436.         if (close_redir(rp))
  437.             status++;
  438.     return status;
  439. }
  440.  
  441. /* devopen --- handle /dev/std{in,out,err}, regular files */
  442. FILE *
  443. devopen (name, mode)
  444. char *name, *mode;
  445. {
  446.     char *cp;
  447.  
  448. #if defined(STRICT)
  449.     return (fopen (name, mode));
  450. #else
  451.     if (strict)
  452.         return (fopen (name, mode));
  453.  
  454.     if (!STREQN (name, "/dev/", 5))
  455.         return (fopen (name, mode));
  456.     else
  457.         cp = name + 5;
  458.         
  459.     /* XXX - first three tests ignore mode */
  460.     if (STREQ(cp, "stdin"))
  461.         return (stdin);
  462.     else if (STREQ(cp, "stdout"))
  463.         return (stdout);
  464.     else if (STREQ(cp, "stderr"))
  465.         return (stderr);
  466.     else
  467.         return (fopen (name, mode));
  468. #endif
  469. }
  470.  
  471. static IOBUF *
  472. gawk_popen(cmd, rp)
  473. char *cmd;
  474. struct redirect *rp;
  475. {
  476.     FILE *fp = popen(cmd, "r");
  477.     return (rp->iop = iop_alloc(fp));
  478. }
  479.  
  480. static int
  481. gawk_pclose(rp)
  482. struct redirect *rp;
  483. {
  484.     pclose (rp->iop->fp);
  485.     rp->iop->fp = NULL;
  486.     return iop_close(rp->iop);
  487. }
  488.  
  489. #define    DO_END_OF_BUF    len = bp - iop->off;\
  490.             used = last - start;\
  491.             while (len + used > iop->secsiz) {\
  492.                 iop->secsiz *= 2;\
  493.                 erealloc(iop->secbuf,char *,iop->secsiz,"get");\
  494.             }\
  495.             last = iop->secbuf + used;\
  496.             start = iop->secbuf;\
  497.             memcpy(last, iop->off, len);\
  498.             last += len;\
  499.             iop->cnt = fread(iop->buf, 1, iop->size, iop->fp);\
  500.             if (iop->cnt == 0 && (feof(iop->fp) || ferror(iop->fp)))\
  501.                 return iop->cnt = -1;\
  502.             end_data = iop->buf + iop->cnt;\
  503.             iop->off = bp = iop->buf;
  504.  
  505. #define    DO_END_OF_DATA    iop->cnt = fread(end_data, 1, end_buf - end_data, iop->fp);\
  506.             if (iop->cnt == 0 && (feof(iop->fp) || ferror(iop->fp)))\
  507.                 return iop->cnt = -1;\
  508.             end_data += iop->cnt;\
  509.             if (iop->cnt == 0)\
  510.                 break;\
  511.             iop->cnt = end_data - iop->buf;
  512.  
  513. static int
  514. get_a_record(res, iop)
  515. char **res;
  516. IOBUF *iop;
  517. {
  518.     register char *end_data;
  519.     register char *end_buf;
  520.     char *start;
  521.     register char *bp;
  522.     register char *last;
  523.     int len, used;
  524.     register char rs = get_rs();
  525.  
  526.     if (iop->cnt < 0)
  527.         return iop->cnt;
  528.  
  529.     /* Only needed if input from the terminal and output to the terminal,
  530.        but (as usual) no way of telling... So do it every time. Maybe
  531.        remove later, as the overhead could be vast! */
  532.     fflush(stdout);
  533.  
  534.     end_data = iop->buf + iop->cnt;
  535.     if (iop->off >= end_data) {
  536.         iop->cnt = fread(iop->buf, 1, iop->size, iop->fp);
  537.         if (iop->cnt == 0 && (feof(iop->fp) || ferror(iop->fp)))
  538.             return iop->cnt = EOF;
  539.         end_data = iop->buf + iop->cnt;
  540.         iop->off = iop->buf;
  541.     }
  542.     last = start = bp = iop->off;
  543.     end_buf = iop->buf + iop->size;
  544.     if (rs == 0) {
  545.         while (!(*bp == '\n' && bp != iop->buf && bp[-1] == '\n')) {
  546.             if (++bp == end_buf) {
  547.                 DO_END_OF_BUF
  548.             }
  549.             if (bp == end_data) {
  550.                 DO_END_OF_DATA
  551.             }
  552.         }
  553.         if (*bp == '\n' && bp != iop->off && bp[-1] == '\n') {
  554.             int tmp = 0;
  555.  
  556.             /* allow for more than two newlines */
  557.             while (*bp == '\n') {
  558.                 tmp++;
  559.                 if (++bp == end_buf) {
  560.                     DO_END_OF_BUF
  561.                 }
  562.                 if (bp == end_data) {
  563.                     DO_END_OF_DATA
  564.                 }
  565.             }
  566.             iop->off = bp;
  567.             bp -= 1 + tmp;
  568.         } else if (bp != iop->buf && bp[-1] != '\n') {
  569.             warning("record not terminated");
  570.             iop->off = bp + 2;
  571.         } else {
  572.             bp--;
  573.             iop->off = bp + 2;
  574.         }
  575.     } else {
  576.         while (*bp++ != rs) {
  577.             if (bp == end_buf) {
  578.                 DO_END_OF_BUF
  579.             }
  580.             if (bp == end_data) {
  581.                 DO_END_OF_DATA
  582.             }
  583.         }
  584.         if (*--bp != rs) {
  585.             warning("record not terminated");
  586.             bp++;
  587.         }
  588.         iop->off = bp + 1;
  589.     }
  590.     if (start == iop->secbuf) {
  591.         len = bp - iop->buf;
  592.         if (len > 0) {
  593.             used = last - start;
  594.             while (len + used > iop->secsiz) {
  595.                 iop->secsiz *= 2;
  596.                 erealloc(iop->secbuf,char *,iop->secsiz,"get2");
  597.             }
  598.             last = iop->secbuf + used;
  599.             start = iop->secbuf;
  600.             memcpy(last, iop->buf, len);
  601.             last += len;
  602.         }
  603.     } else
  604.         last = bp;
  605.     *last = '\0';
  606.     *res = start;
  607.     return last - start;
  608. }
  609.  
  610. NODE *
  611. do_getline(tree)
  612. NODE *tree;
  613. {
  614.     struct redirect *rp;
  615.     IOBUF *iop;
  616.     int cnt;
  617.     NODE **lhs;
  618.     int redir_error = 0;
  619.  
  620.     if (tree->rnode == NULL) {     /* no redirection */
  621.         iop = nextfile();
  622.         if (iop == NULL)        /* end of input */
  623.             return tmp_number((AWKNUM) 0.0);
  624.     } else {
  625.         rp = redirect(tree->rnode, &redir_error);
  626.         if (rp == NULL && redir_error)    /* failed redirect */
  627.             return tmp_number((AWKNUM) -1.0);
  628.         iop = rp->iop;
  629.         getline_redirect++;
  630.     }
  631.     if (tree->lnode == NULL) {    /* no optional var. -- read in $0 */
  632.         if (inrec(iop) != 0) {
  633.             getline_redirect = 0;
  634.             return tmp_number((AWKNUM) 0.0);
  635.         }
  636.     } else {            /* read in a named variable */
  637.         char *s = NULL;
  638.  
  639.         lhs = get_lhs(tree->lnode, 1);
  640.         cnt = get_a_record(&s, iop);
  641.         if (!getline_redirect) {
  642.             assign_number(&NR_node->var_value,
  643.                 NR_node->var_value->numbr + 1.0);
  644.             assign_number(&FNR_node->var_value,
  645.                 FNR_node->var_value->numbr + 1.0);
  646.         }
  647.         if (cnt == EOF) {
  648.             getline_redirect = 0;
  649.             free(s);
  650.             return tmp_number((AWKNUM) 0.0);
  651.         }
  652.         *lhs = make_string(s, strlen(s));
  653.         do_deref();
  654.         /* we may have to regenerate $0 here! */
  655.         if (field_num == 0)
  656.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  657.         field_num = -1;
  658.     }
  659.     getline_redirect = 0;
  660.     return tmp_number((AWKNUM) 1.0);
  661. }
  662.